//
//  main.m
//  MRC_Test
//
//  Created by admin on 2019/7/30.
//  Copyright © 2019 猫爷爷的酱醋茶. All rights reserved.
//

/*
 
 内存管理：
 1.概念：只需要管理存储在堆中的OC对象的回收，其他区域中的数据的回收是系统自动管理的。
 2.方式：
 1）MRC：Manual Reference Counting -- 手动引用计数器/手动内存管理
 2）ARC：Automatic Reference Counting -- 自动引用计数器
 
 内存泄漏：
 指的是一个对象没有被及时回收，一直驻留在内存中，直到程序结束的时候才回收。
 1）单个对象的内存泄漏的情况
 a。有对象的创建，而没有对应的release
 b。retain的次数和release的次数不匹配
 c。在不适当的时候，为指针赋值为nil
 
 2）多个对象的内存管理
 1.当属性是一个OC对象的时候，setter方法的写法
 将传进来的对象赋值给当前对象的属性，代表传入的对象多了一个人使用，所以应该先为这个传入的对象发送一条retain消息，再赋值
 当当前对象被销毁的时候，代表属性指向的对象少一个人使用，就应该在dealloc中release
 
 代码写法：
 -(void)setCar:(Car *)car
 {
    if(_car != car)//说明新旧对象不一样
    {
     [_car release];   //当第一次执行的时候，_car = nil，不执行不报错
     _car = [car retain];
    }
 }
 
 -(void)dealloc
 {
     [_car release];
     [super dealloc];
 }
 
 引用计数器：
 每一个对象都有一个属性，叫做retainCount，默认值为1，数据类型为unsigned long 占据8个字节。
 作用：
 用来记录当前对象被多少个在引用。
 1）当这个对象要多被使用一次的时候，应该先让对象的引用计数器的值+1，代表多一个人在使用；
 2）当这个对象少一个人使用的时候，应该先让对象的引用计数器的值-1，代表少一个人在使用。
 3）当这个对象的引用计数器的值为0的时候，代表这个对象无人使用，这个时候，系统会自动回收这个对象。
 在对象被回收的时候，会自动调用对象的dealloc方法。
 
 如何操作引用计数器：
 1）当多一个人使用的时候，为对象发送一条retain消息，对象的引用计数器就会+1；
 2）当少一个人使用的时候，为对象发送一条release消息，对象的引用计数器就会-1.
 3）要查看对象引用计数器的值的时候，为对象发送一条retainCount消息。
 
 
 1. Xcode默认开启ARC模式，需要关闭ARC，开启MRC；
    因为在ARC机制下，无法调用retain、release、dealloc
 
 2. 在系统回收对象的时候，会自动调用对象的dealloc方法
    重写dealloc方法的规范：
    必须在最后一句代码调用父类的dealloc方法。[super dealloc];
    因为子类中有父类的属性，而父类的其他属性的release是放在父类的dealloc方法之中的，
    所以为了能释放所有对象，必须要调用deallo对象。
 
 3. 测试引用计数器
    新创建一个对象，这个对象的引用计数器的默认值为1.

 4. 内存管理的原则
    a）有对象的创建，就要匹配一个release
    b）retain的次数和release的次数要匹配
    c）谁用谁retain，谁不用谁release
 
 5. 自动释放池
 
     原理：
        存入到自动释放池的对象，在自动释放池被销毁的时候，会自动向存储在该自动释放池中的所有对象发送release消息。
 
     作用：
         将创建的对象放入自动释放池中，就不再需要手动release这个对象了
         因为池子销毁的时候，就会自动调用池中所有的对象的release方法。
 
     语法：如何将对象存储在自动释放池中？
         在自动释放池中调用对象的autorelease方法，就会将对象存入到当前释放池之中。
 
         @autoreleasepool
         {
            Person *p1 = [[[Person alloc] init] autorelease];
         }
 
    创建时间和销毁时间：
        每一次主线程的消息循环（类似死循环，目的让程序一直执行，等待用户的交互）开始的时候会先创建自动释放池，
        运行循环结束前，会释放自动释放池
 
    使用位置：
        1.如果在一个循环里面需要创建很多对象，需要在循环里面添加自动释放池，可以降低内存的消耗（循环很耗CPU）
 
         for(int i = 0;i < 1000000;i++)
         {
            autoreleasepool
             {
                NSString *str = [NSString stringWithFormat:@"hello %d",i];
             }
         }
 
        2.使用NSThread做多线程开发时，需要在子线程调度方法中手动添加自动释放池，因为子线程无法调用主线程的自动释放池
 
 */
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[])
{
    Person *p1 = [[Person alloc]init];
    p1.name = @"猫爷爷的酱醋茶";
    //查看引用计数器的值
    NSUInteger count = [p1 retainCount];
    NSLog(@"count = %lu",count);
   
    //释放对象，让引用计数器的值-1
    //当计数器的值为0时，自动调用dealloc
    [p1 release];
    
    
    return 0;
}
